/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry.samples.ohos;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.Text;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.window.service.WindowManager;
import ohos.app.Environment;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Collections;
import java.util.Locale;

import io.sentry.Attachment;
import io.sentry.ISpan;
import io.sentry.Sentry;
import io.sentry.SpanStatus;
import io.sentry.UserFeedback;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;

/**
 * MainAbility
 *
 * @since 2021-06-02
 */
public class MainAbility extends Ability {
    /**
     * AVAILABLE_BYTE
     */
    public static final int AVAILABLE_BYTE = 1024;
    /**
     * NEGATIVE_ONE
     */
    public static final int NEGATIVE_ONE = -1;
    /**
     * LABEL
     */
    public static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x01, "exception.message");

    /**
     * TEN_THOUSAND
     */
    public static final int TEN_THOUSAND = 10000;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        setUIContent(ResourceTable.Layout_ability_main);
        getWindow().setStatusBarColor(Color.getIntColor("#006666"));
        Text title = (Text) findComponentById(ResourceTable.Id_txt_title);
        title.setFont(Font.DEFAULT_BOLD);
        ResourceManager resManager = getResourceManager();
        RawFileEntry rawFileEntry = resManager.getRawFileEntry("resources/rawfile/sentry.png");
        Resource resource = null;
        try {
            resource = rawFileEntry.openRawFile();
        } catch (IOException e) {
            HiLog.info(LABEL, e.getMessage());
        }
        File imageFile = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "sentry.png");
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(imageFile);
            int index;
            byte[] bytes = new byte[AVAILABLE_BYTE];
            while ((index = resource.read(bytes)) != NEGATIVE_ONE) {
                outputStream.write(bytes, 0, index);
                outputStream.flush();
            }
        } catch (IOException e) {
            Sentry.captureException(e);
        } finally {
            try {
                resource.close();
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                HiLog.info(LABEL, e.getMessage());
            }
        }
        try {
            Attachment image = new Attachment(imageFile.getCanonicalPath(), "sentry.png", "image/png");
            Sentry.configureScope(
                scope -> {
                    scope.addAttachment(image);
                });
        } catch (IOException e) {
            e.printStackTrace();
        }

        initListener();
    }

    @Override
    protected void onActive() {
        super.onActive();
        final ISpan span = Sentry.getSpan();
        if (span != null) {
            span.finish(SpanStatus.OK);
        }
    }

    private void initListener() {
        findComponentById(ResourceTable.Id_crash_from_java).setClickedListener(component -> {
            throw new RuntimeException("Uncaught Exception from Java.");
        });
        findComponentById(ResourceTable.Id_send_message).setClickedListener(component -> {
            Sentry.captureMessage("Some message.");
        });
        String email = "john@me.com";
        findComponentById(ResourceTable.Id_send_user_feedback).setClickedListener(component -> {
            SentryId sentryId = Sentry.captureException(new Exception("I have feedback"));
            UserFeedback userFeedback = new UserFeedback(sentryId);
            userFeedback.setComments("It broke on Ohos. I don't know why, but this happens.");
            userFeedback.setEmail(email);
            userFeedback.setName("John Me");
            Sentry.captureUserFeedback(userFeedback);
        });
        initAttachment();
        findComponentById(ResourceTable.Id_capture_exception).setClickedListener(component -> {
            Sentry.captureException(new Exception(new Exception(new Exception("Some exception."))));
        });
        findComponentById(ResourceTable.Id_breadcrumb).setClickedListener(component -> {
            Sentry.addBreadcrumb("Breadcrumb");
            Sentry.setExtra("extra", "extra");
            Sentry.setFingerprint(Collections.singletonList("fingerprint"));
            Sentry.setTransaction("transaction");
            Sentry.captureException(new Exception("Some exception with scope."));
        });
        findComponentById(ResourceTable.Id_unset_user).setClickedListener(component -> {
            Sentry.setTag("user_set", "null");
            Sentry.setUser(null);
        });
        initSetUser();
        findComponentById(ResourceTable.Id_native_crash).setClickedListener(component -> {
            NativeSample.crash();
        });
        findComponentById(ResourceTable.Id_native_capture).setClickedListener(component -> {
            NativeSample.message();
        });
        findComponentById(ResourceTable.Id_anr).setClickedListener(component -> {
            // Try cause ANR by blocking for 10 seconds.
            // By default the SDK sends an event if blocked by at least 5 seconds.
            // Keep clicking on the ANR button till you've gotten the "App. isn''t responding" dialog,
            // then either click on Wait or Close, at this point you should have seen an event on
            // Sentry.
            // NOTE: By default it doesn't raise if the debugger is attached. That can also be
            // configured.
            try {
                Thread.sleep(TEN_THOUSAND);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        initOpenSecondAbility();
    }

    private void initAttachment() {
        findComponentById(ResourceTable.Id_add_attachment).setClickedListener(component -> {
            String fileName = Calendar.getInstance().getTimeInMillis() + "_file.txt";
            File file = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
            try (FileOutputStream fileOutputStream = new FileOutputStream(file);
                 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
                 Writer writer = new BufferedWriter(outputStreamWriter)) {
                for (int i = 0; i < AVAILABLE_BYTE; i++) {
                    // To keep the sample code simple this happens on the main thread. Don't do this in a
                    // real app.
                    writer.write(String.format(Locale.getDefault(), "%d" + System.lineSeparator(), i));
                }
                writer.flush();
            } catch (IOException e) {
                Sentry.captureException(e);
            }
            Sentry.configureScope(
                scope -> {
                    String json = "{ \"number\": 10 }";
                    Attachment attachment = new Attachment(json.getBytes(Charset.forName("UTF-8")), "log.json");
                    scope.addAttachment(attachment);
                    scope.addAttachment(new Attachment(file.getPath()));
                });
        });
    }

    private void initSetUser() {
        findComponentById(ResourceTable.Id_set_user).setClickedListener(component -> {
            Sentry.setTag("user_set", "instance");
            User user = new User();
            user.setUsername("username_from_java");
            user.setEmail("email_from_java");
            user.setIpAddress("{{auto}}");
            Sentry.setUser(user);
        });
    }

    private void initOpenSecondAbility() {
        findComponentById(ResourceTable.Id_open_second_ability).setClickedListener(component -> {
            terminateAbility();
            Intent intent2 = new Intent();
            Operation operation = new Intent.OperationBuilder()
                .withBundleName(getBundleName())
                .withAbilityName(SecondAbility.class)
                .build();
            intent2.setOperation(operation);
            startAbility(intent2);
        });
    }
}
